import java.io.File

import Tool.isNX
import org.apache.commons.lang3.StringUtils

import scala.collection.mutable
import scala.io.Source

/**
  * Created by yz on 2019/1/31
  */
object Implicits {

  implicit class MyFile(val file: File) {

    def lines = Utils.txt2Lines(file)

  }

  implicit class MyLines1(val lines: Stream[String]) {

    def filterByColumns(f: mutable.Buffer[String] => Boolean) = {
      lines.filter { line =>
        val columns = Utils.splitByTab(line)
        f(columns)
      }
    }

    def mapByColumns(n: Int, f: mutable.Buffer[String] => mutable.Buffer[String]) = {
      lines.take(n) ++ lines.drop(n).map { line =>
        val columns = Utils.splitByTab(line)
        val newColumns = f(columns)
        newColumns.mkString("\t")
      }

    }

    //    def mapByColumns(f: mutable.Buffer[String] => mutable.Buffer[String]): mutable.Buffer[String] = {
    //      mapByColumns(0, f)
    //    }

    def mapOtherByColumns[T](f: mutable.Buffer[String] => T) = {
      lines.map { line =>
        val columns = Utils.splitByTab(line)
        f(columns)
      }

    }

    def headers = lines.head.split("\t").toBuffer


  }

  implicit class MyLines(val lines: mutable.Buffer[String]) {

    def filterByColumns(f: mutable.Buffer[String] => Boolean) = {
      lines.filter { line =>
        val columns = Utils.splitByTab(line)
        f(columns)
      }
    }

    def mapByColumns(n: Int, f: mutable.Buffer[String] => mutable.Buffer[String]): mutable.Buffer[String] = {
      lines.take(n) ++= lines.drop(n).map { line =>
        val columns = Utils.splitByTab(line)
        val newColumns = f(columns)
        newColumns.mkString("\t")
      }

    }

    def mapByColumns(f: mutable.Buffer[String] => mutable.Buffer[String]): mutable.Buffer[String] = {
      mapByColumns(0, f)
    }

    def mapOtherByColumns[T](f: mutable.Buffer[String] => T) = {
      lines.map { line =>
        val columns = Utils.splitByTab(line)
        f(columns)
      }

    }

    def headers = lines.head.split("\t")


  }


  implicit class SnpLines(val lines: mutable.Buffer[String]) {

    def nxfiy = {
      lines.mapByColumns(1, { columns =>
        columns.take(3) ++= columns.drop(3).map { v =>
          if (v.distinct.size == 1) {
            v(0).toString
          } else "X"
        }
      })

    }

    def filterEmptyPos = {
      lines.filterByColumns { columns =>
        StringUtils.isNotEmpty(columns(2))
      }

    }

    def filterRow(rowRate: Double) = {
      lines.filterByColumns { columns =>
        val values = columns.drop(3)
        val nxs = values.filter(x => isNX(x))
        nxs.size / values.size.toDouble < rowRate
      }
    }

    def idInfos = {
      lines.drop(1).zipWithIndex.map { case (line, i) =>
        val columns = line.split("\t")
        IdInfo(columns(0), columns(1), columns(2).toInt, i)
      }
    }

    def sampleGenesMap = {
      val headers = lines.headers
      val sampleMap = headers.drop(3).map { column =>
        column -> new StringBuilder()
      }.toMap
      lines.drop(1).foreach { line =>
        val columns = line.split("\t")
        columns.zipWithIndex.drop(3).foreach { case (v, i) =>
          val header = headers(i)
          sampleMap(header).append(v)
        }
      }
      sampleMap
    }


  }

  implicit class SnpLines1(val lines: Stream[String]) {

    def nxfiy = {
      lines.mapByColumns(1, { columns =>
        columns.take(3) ++= columns.drop(3).map { v =>
          if (v.distinct.size == 1) {
            v(0).toString
          } else "X"
        }
      })

    }

    def filterEmptyPos = {
      lines.filterByColumns { columns =>
        StringUtils.isNotEmpty(columns(2))
      }

    }

    def filterRow(rowRate: Double) = {
      lines.filterByColumns { columns =>
        val values = columns.drop(3)
        val nxs = values.filter(x => isNX(x))
        nxs.size / values.size.toDouble < rowRate
      }

    }

    def getNeedInfos = {
      val idInfos=mutable.Buffer[IdInfo]()
      val headers = lines.headers
      val sampleMap = headers.drop(3).map { column =>
        column -> new StringBuilder()
      }.toMap
      val startTime = System.currentTimeMillis()
      println(headers.size)
      lines.drop(1).zipWithIndex.foreach { case(line,i) =>
        if (i % 5000 == 0) {
          println(s"${i}\t${Utils.getTime(startTime)}")
        }
        val columns = line.split("\t")
        val idInfo=IdInfo(columns(0), columns(1), columns(2).toInt, i)
        idInfos+=idInfo
        columns.zipWithIndex.drop(3).foreach { case (v, i) =>
          val header = headers(i)
          sampleMap(header).append(v)
        }
      }
      (idInfos,sampleMap)
    }


  }

  implicit class RegionLines(val lines: mutable.Buffer[String]) {

    def regionDatas = {
      lines.drop(1).mapOtherByColumns { columns =>
        RegionData(columns(0), columns(1).toInt,
          columns(2).toInt)
      }
    }

  }


}
